package com.hua.nailcampus.socket;

import com.hua.nailcampus.acl.mapper.MessagesMapper;
import com.hua.nailcampus.acl.mapper.UserMapper;
import com.hua.nailcampus.acl.model.Messages;
import com.hua.nailcampus.acl.model.User;
import jakarta.annotation.Resource;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @Program: springboot_websocket
 * @ClassName WebsocketServer
 * @Author: chenjianhua
 * @Description: websocket服务
 * @Create: 2022-08-19 18:52
 * @Version 1.0
 **/
@Slf4j
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketServer {
    //    在线人数
    private static int onlineCount;
    //    当前会话
    private Session session;
    //    用户唯一标识
    private  String userId;

    @Resource
    private MessagesMapper messagesMapper;

    private static UserMapper userMapper;
    @Autowired
    public void setUserService(UserMapper userMapper){
        WebSocketServer.userMapper = userMapper;
    }


    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * concurrent包的线程安全set，用来存放每个客户端对应的MyWebSocket对象
     */
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap();

    /**
     * 为了保存在线用户信息，在方法中新建一个list存储一下【实际项目依据复杂度，可以存储到数据库或者缓存】
     */
    private final static List<Session> SESSIONS = Collections.synchronizedList(new ArrayList<>());

    /**
     * @methodName: onOpen
     * @description: 建立连接
     * @Author chenjianhua
     * @param  session, userId
     * @updateTime 2022/8/19 19:31
     * @return void
     * @throws
     **/
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        webSocketSet.add(this);
        SESSIONS.add(session);
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId,this);
        } else {
            webSocketMap.put(userId,this);
            addOnlineCount();
        }
        User user = userMapper.selectById(userId);
        user.setStatus(true);
        userMapper.updateById(user);
        log.info("[用户ID:{}已上线], 当前连接数:{}", this.userId, getOnlineCount());
    }

    /**
     * @methodName: onClose
     * @description: 断开连接
     * @Author chenjianhua
     * @param
     * @updateTime 2022/8/19 19:31
     * @return void
     * @throws
     **/
    @OnClose
    public void onClose() {
        log.info("用户ID：{}已下线",userId);
        webSocketSet.remove(this);
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            subOnlineCount();
        }
        User user = userMapper.selectById(userId);
        user.setStatus(false);
        userMapper.updateById(user);
    }

    /**
     * @methodName: onError
     * @description: 发送错误
     * @Author chenjianhua
     * @param  session, error]
     * @updateTime 2022/8/19 19:32
     * @return void
     * @throws
     **/
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("[连接ID:{}] 错误原因:{}", this.userId, error.getMessage());
        error.printStackTrace();
    }

    /**
     * @methodName: onMessage
     * @description: 收到消息
     * @Author chenjianhua
     * @param  message
     * @updateTime 2022/8/19 19:32
     * @return void
     * @throws
     **/
    @OnMessage
    public void onMessage(String message) {
//        将信息存入数据库中
        log.info("[连接ID:{}] 收到消息:{}", this.userId, message);
//        this.sendMessage(message,this.userId,this.userId);
    }

    /**
     * @methodName: sendMessage
     * @description: 发送消息
     * @Author chenjianhua
     * @param  content, toUserId, fromUserId
     * @updateTime 2022/8/19 19:32
     * @return void
     * @throws
     **/
    public void  sendMessage(String content,String toUserId,String fromUserId) {
        Messages messages = new Messages();
        Messages messages1 = new Messages();
        WebSocketServer webSocketServer = webSocketMap.get(toUserId);
        messages.setFromUserID(Integer.parseInt(fromUserId));
        messages.setToUserID(Integer.parseInt(toUserId));
        messages.setContent(content);
        messages.setBelongId(Integer.parseInt(fromUserId));
        messages1.setFromUserID(Integer.parseInt(fromUserId));
        messages1.setToUserID(Integer.parseInt(toUserId));
        messages1.setContent(content);
        messages1.setBelongId(Integer.parseInt(toUserId));
            try {
                if(webSocketServer==null){
                    messagesMapper.insert(messages);
                    messagesMapper.insert(messages1);
                    log.info("执行到了这里");
                }else{
                    messages.setStatus(false);
                    content = fromUserId+":"+content;
                    webSocketServer.session.getBasicRemote().sendText(content);
                    messagesMapper.insert(messages);
                    messagesMapper.insert(messages1);
                    log.info("【websocket消息】推送消息,[toUser]userId={},message={}", toUserId,content);
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.error("[连接ID:{}] 发送消息失败, 消息:{}", this.userId, content, e);
            }
    }

    /**
     * @methodName: sendMassMessage
     * @description: 群发消息
     * @Author chenjianhua
     * @param  message
     * @updateTime 2022/8/19 19:33
     * @return void
     * @throws
     **/
    public void sendMassMessage(String message) {
        try {
            for (Session session : SESSIONS) {
                if (session.isOpen()) {
                    session.getBasicRemote().sendText(message);
                    log.info("[连接ID:{}] 发送消息:{}",session.getRequestParameterMap().get("userId"),message);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取当前连接数
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 当前连接数加一
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 当前连接数减一
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}